﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Windows.Controls;
using static 摸鱼._数据库;
using System.Windows.Forms;
using static 摸鱼._数据库._方案._步骤;
using static 摸鱼.全局类;
using static 摸鱼.核心._数据;
using System.Collections;
using OpenCvSharp;
using static 摸鱼.核心;
using static 摸鱼._数据库._方案;
using static 摸鱼.键鼠.钩子;
using Newtonsoft.Json.Linq;
using static 摸鱼.核心._数据._AsyncData;

namespace 摸鱼
{
    public static class 核心
    {
        public static void 启动(_数据库._方案 启动方案, _数据库._方案._步骤 启动步骤)
        {
            if (启动方案 == null)
                return;
            if (线程s.ContainsKey(启动方案))
            {
                声音.已开始(数据库.参数[CS.全局音量].音量, 多线程: true);
                return;
            }

            声音.开始(数据库.参数[CS.全局音量].音量, 多线程: true);
            线程s[启动方案] = new();
            var 线程列表item = 线程s[启动方案];

            MoyuThreadPool.Post(() =>
            {
                TryCatch(() =>
                {
                    //空方案空步骤判断
                    if (启动方案.步骤.Count == 0)
                        return;
                    int 初始步骤 = 启动步骤 == null ? 0 : 启动方案.步骤.IndexOf(启动步骤) == -1 ? 0 : 启动方案.步骤.IndexOf(启动步骤);
                    Debug.WriteLine("启动线程 " + Thread.CurrentThread.ManagedThreadId);
                    方法Action.初始化();

                    //拿到结束权
                    MainWindow.任务s.Enqueue(() =>
                    {
                        线程列表item.控件节点 = new() { Tag = 启动方案, Header = 启动方案.名字 };
                        MainWindow.This.线程列表.Items.Add(线程列表item.控件节点);
                    });

                    线程列表item.数据 = new(初始步骤, 启动方案);
                    执行步骤(线程列表item.数据, true);
                    线程结束收尾(启动方案);
                }, () =>
                {
                    //if (启动方案.名字 == "监控碎星数量")
                    //    Debugger.Break();
                    线程结束收尾(启动方案);
                });
            });
        }

        public static void 线程结束收尾(_方案 方案)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (线程s.TryRemove(方案, out var item))
                {
                    声音.结束(数据库.参数[CS.全局音量].音量, 多线程: true);
                    item.Dispose();
                }
            });

            //重置选中步骤
            if (方案 == 数据库.当前方案)
                MainWindow.任务s.Enqueue(() =>
                {
                    if (MainWindow.This.步骤列表.Items.Count != 0)
                        ((TreeViewItem)MainWindow.This.步骤列表.Items[0]).IsSelected = true;
                });

            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
        public static void 执行步骤(_数据 数据, bool 等待异步结束)
        {
            while (数据.Steps.TryDequeue(out int bz))
            {
                _步骤 步骤 = 数据.方案.步骤[bz];
                if (is屏蔽步骤(in bz))
                    continue;

                if (步骤.参数[CS.异步][valueType.Bool] && !数据.AsyncDatas.ContainsKey(步骤))
                {
                    数据.AsyncDatas.TryAdd(步骤, default);
                    MoyuThreadPool.Post(() =>
                    {
                        TryCatch(() =>
                        {
                            数据.AsyncDatas[步骤] = new(数据, bz, true, null);
                            执行步骤(数据, false);
                        }, () =>
                        {
                            if (数据.AsyncDatas is not null)
                                数据.AsyncDatas[步骤].ActionEnd = true;
                        });
                    });

                }
                else
                {
                    数据.threadData.Return = 0;
                    执行方法s(数据, 步骤, 步骤.方法, default, new() { 循环num = 1 });
                }
            }
            if (!等待异步结束)
                return;

            MoyuDelay.Star(20);
            自旋(() =>
            {
                foreach (var item in 数据.AsyncDatas.GetEnumerable())
                {
                    if (item != null && !item.ActionEnd)
                        return false;
                }
                return true;
            });
            return;

            bool is屏蔽步骤(in int bz)
            {
                if (数据.屏蔽步骤.TryGetValue(bz, out double endTime))
                {
                    if (时间戳 > endTime)
                        数据.屏蔽步骤.Remove(bz);
                    else
                        return true;
                }
                return false;
            }
        }


        public static void 执行方法s(_数据 数据, _步骤 步骤, List<_方法> 方法s, _方法 父方法, _方法data 父方法data)
        {
            while (父方法data.循环num-- > 0)
            {
                int i = 0;
                List<_方法> 实时方法s = new(方法s);
                while (i < 实时方法s.Count)
                {
                    _方法 方法 = 实时方法s[i];
                    数据.方法datas.TryAdd(方法, new());
                    var 方法data = 数据.方法datas[方法];

                    //----有预约的方法吗
                    if (数据.预约方法s.TryRemove(方法.名字, out var 预约item))
                    {
                        if (预约item.延迟num-- == 0)
                        {
                            实时方法s.Insert(i, 预约item.方法);
                            continue;
                        }
                        else
                            数据.预约方法s.TryAdd(方法.名字, 预约item);
                    }

                    //----当前方法
                    方法Action.Do(数据, 步骤, 方法, 方法data);
                    方法data.信号.IFEXIT();
                    if (isReturn(数据.threadData, 父方法data))
                        return;
                    else if (isBreak(数据.threadData, 父方法data))
                        break;

                    //----子方法
                    执行方法s(数据, 步骤, 方法.子, 方法, 方法data);
                    if (isReturn(数据.threadData, 父方法data))
                        return;
                    else if (isBreak(数据.threadData, 父方法data))
                        break;
                    i++;
                }
                父方法data.信号.IFEXIT();
                //如果循环尾调用为false，则每次循环都不会执行父方法
                if (父方法data.循环尾调用-- > 0)
                    方法Action.Do(数据, 步骤, 父方法, 父方法data);
            }
        }
        private static bool isBreak(返回数据 threadData, _方法data 父方法data)
        {
            if (threadData.调用父方法)
            {
                threadData.调用父方法 = false;
                父方法data.循环尾调用 = 1;
                return true;
            }
            else if (threadData.跳过后续方法)
            {
                threadData.跳过后续方法 = false;
                return true;
            }
            return false;
        }
        private static bool isReturn(返回数据 threadData, _方法data 父方法data)
        {
            if (threadData.Return > 0)
            {
                threadData.Return--;
                return true;
            }
            if (threadData.stoploop)
            {
                父方法data.循环num = 0;
                threadData.stoploop = false;
            }
            return false;
        }

        public static void 解除阻塞并结束(_方案 方案)
        {
            if (方案 == null || 线程s[方案]?.数据?.方法datas == null)
            {
                MoyuControl.Msgbox("解除阻塞并结束时, 数据 == null");
                return;
            }
            foreach (var item in 线程s[方案].数据.方法datas.Values)
                item.信号?.ExitThread();
        }

        public static void 冷却(object sender, EventArgs e)
        {
            BlockInput(false);
            键鼠.钩子.共享内存2.数据.鼠标锁 = false;
            键鼠.钩子.共享内存2.访问器.Write(0, ref 键鼠.钩子.共享内存2.数据);
            //单独结束判断
            if (sender is TreeViewItem treeView && treeView.Tag is _方案 线程item)
            {
                解除阻塞并结束(线程item);
                return;
            }
            //全部结束
            foreach (var item in 线程s)
            {
                try
                {
                    if (item.Key.参数[CS.线程锁].值 == "0" || (sender is int x) && x == 2)
                        解除阻塞并结束(item.Key);
                }
                catch (Exception k)
                {
                    Debug.WriteLine($"找不到要结束的方案, 错误：{k.Message}");
                }
            }
        }
        public class 返回数据
        {
            public string 返回值;
            public int Return;
            public bool stoploop;
            public bool 调用父方法;
            public bool 跳过后续方法;
        }

        public class _数据 : IDisposable
        {
            public _方案 方案;
            public bool 被调用;
            public double 时间筛查;
            public _AsyncData AsyncDatas = new();
            public ThreadLocal<Queue<int>> _Steps = new();
            public Dictionary<int, double> 屏蔽步骤 = new();
            public ThreadLocal<返回数据> _threadData = new();
            public ConcurrentHashSet<_参数> 参数事件s = new();
            public ConcurrentHashSet<string> 订阅暗号s = new();
            public ConcurrentDictionary<_方法, _方法data> 方法datas = new();
            public (Stopwatch 计时器, long 偏移量) 时间分割器 = new(new(), 0);
            public ConcurrentDictionary<string, (_方法 方法, int 延迟num)> 预约方法s = new();

            public Queue<int> Steps
            {
                get => _Steps.Value;
                set => _Steps.Value = value;
            }
            public 返回数据 threadData
            {
                get => _threadData.Value;
                set => _threadData.Value = value;
            }
            public _数据(int 初始步骤, _数据库._方案 方案)
            {
                this.方案 = 方案;
                Steps = new();
                threadData = new();
                初始化步骤队列(方案, 初始步骤);
            }
            public _数据(int 初始步骤, _数据库._方案 方案, ConcurrentDictionary<_方法, _方法data> 方法Datas)
            {
                this.方案 = 方案;
                Steps = new();
                threadData = new();
                初始化步骤队列(方案, 初始步骤);
                方法datas = 方法Datas;
            }
            public void Dispose()
            {
                foreach (var item in 参数事件s)
                    核心.参数事件s.TryRemove(item, out _);
                参数事件s.Clear();
                参数事件s = null;

                if (方法datas != null)
                {
                    foreach (var 方法data in 方法datas.Values)
                    {
                        if (方法data.键盘事件 != null)
                            键鼠.钩子.键盘Click -= 方法data.键盘事件;
                        if (方法data.鼠标事件 != null)
                            键鼠.钩子.鼠标Click -= 方法data.鼠标事件;
                        if (方法data.控件 != null)
                        {
                            if (方法data.Dwm绑定句柄 != default)
                                方法data.控件.Invoke(() =>
                                {
                                    Win32.DwmUnregisterThumbnail(方法data.Dwm绑定句柄);
                                    方法data.控件.Visible = false;
                                    方法data.控件.Dispose();
                                });
                            else
                                前景窗口.Post(() =>
                                {
                                    前景窗口.窗体.Controls.Remove(方法data.控件);
                                    方法data.控件.Dispose();
                                    方法data.控件 = null;
                                });
                        }
                        if (方法data.私有数据 != null)
                        {
                            方法data.私有数据.方法datas = null;
                            方法data.私有数据.Dispose();
                        }
                        var 已按下按键s = 方法data.已按下按键s;
                        if (已按下按键s.Count != 0)
                        {
                            foreach (var key in 已按下按键s)
                            {
                                var bscan = Win32.扫描码get(key);
                                Win32.keybd_event((byte)key, (byte)bscan, 2, 0);
                            }
                        }
                        方法data.已按下按键s.Clear();
                        方法data.isDispose = true;
                    }
                    方法datas.Clear();
                    方法datas = null;
                }
                foreach (var item in 订阅暗号s)
                {
                    if (消息s.TryGetValue(item, out var value))
                    {
                        消息s.Remove(item, out _);
                        value.Dispose();
                        value = null;
                    }
                }
                订阅暗号s.Clear();

                方案 = null;
                时间分割器 = default;
                AsyncDatas.Dispose();
                AsyncDatas = null;
            }

            public class _方法data
            {
                public double 时间;
                public int 循环num;
                public int 循环尾调用;
                public bool isDispose;
                public _数据 私有数据;
                public IntPtr Dwm绑定句柄;
                public int 第几次循环 = -1;
                public bool 第一次执行 = true;
                public System.Drawing.Point 坐标;
                public MoyuWait 信号 = new(false);
                public Action<List<int>, bool> 键盘事件;
                public Action<List<int>, bool> 鼠标事件;
                public System.Windows.Forms.Control 控件;
                public ConcurrentHashSet<Keys> 已按下按键s = new();
                public System.Collections.Generic.Dictionary<int, bool> 按键;
            }

            public class _AsyncData : IDisposable, IEnumerable
            {
                public ConcurrentDictionary<_方法, __AsyncData> datas1 = new();
                public ConcurrentDictionary<_步骤, __AsyncData> datas2 = new();

                public __AsyncData this[_方法 方法]
                {
                    get => datas1[方法];
                    set => datas1[方法] = value;
                }
                public __AsyncData this[_步骤 步骤]
                {
                    get => datas2[步骤];
                    set => datas2[步骤] = value;
                }
                public bool TryAdd(_方法 key, __AsyncData value) => datas1.TryAdd(key, value);
                public bool TryAdd(_步骤 key, __AsyncData value) => datas2.TryAdd(key, value);
                public bool ContainsKey(_方法 key) => datas1.ContainsKey(key);
                public bool ContainsKey(_步骤 key) => datas2.ContainsKey(key);
                public bool Remove(_方法 key) => datas1.Remove(key, out _);
                public bool Remove(_步骤 key) => datas2.Remove(key, out _);
                public __AsyncData[] GetEnumerable() => [.. datas1.Values, .. datas2.Values];
                public IEnumerator<__AsyncData> GetEnumerator() => (IEnumerator<__AsyncData>)GetEnumerable().GetEnumerator();
                IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

                public void Dispose()
                {
                    datas1.Clear();
                    datas2.Clear();
                    datas1 = null;
                    datas2 = null;
                }

                public class __AsyncData
                {
                    private _数据 数据;
                    private _方法 根方法;
                    private bool _actionEnd;
                    public bool ActionEnd
                    {
                        get => _actionEnd;
                        set
                        {
                            if (value && 根方法 != null)
                            {
                                List<Keys> keys = new();
                                寻找子方法按键(根方法.子, in keys);
                                void 寻找子方法按键(List<_方法> items, in List<Keys> keys)
                                {
                                    foreach (var item in items)
                                    {
                                        if (数据.方法datas.TryGetValue(item, out var value))
                                        {
                                            var 方法keys = value.已按下按键s;
                                            if (方法keys != null && 方法keys.Count != 0)
                                            {
                                                keys.AddRange(方法keys);
                                                方法keys = null;
                                                value.已按下按键s.Clear();
                                            }
                                            寻找子方法按键(item.子, in keys);
                                        }
                                    }
                                }

                                if (keys.Count != 0)
                                {
                                    foreach (var key in keys)
                                    {
                                        var bscan = Win32.扫描码get(key);
                                        Win32.keybd_event((byte)key, (byte)bscan, 2, 0);
                                    }
                                }
                                keys.Clear();
                            }
                            _actionEnd = value;
                        }
                    }

                    public __AsyncData(_数据 数据, int 初始步骤, bool 单步, _方法 根方法)
                    {
                        this.数据 = 数据;
                        this.根方法 = 根方法;
                        数据.Steps = new();
                        数据.threadData = new();
                        if (单步)
                            数据.Steps.Enqueue(初始步骤);
                        else
                            数据.初始化步骤队列(数据.方案, 初始步骤);
                    }
                }
            }
            public void 初始化步骤队列(_方案 方案item, int 初始步骤)
            {
                Steps.Clear();
                for (int i = 0; i < 方案item.步骤.Count; i++)
                    if (i >= 初始步骤)
                        Steps.Enqueue(i);

            }
        }

        //----跨方案全局数据
        public static ConcurrentDictionary<string, BlockingQueue<string>> 消息s = new();
        public static ConcurrentDictionary<_参数, Action> 参数事件s = new();
        public static ConcurrentDictionary<_方案, _线程列表> 线程s = new();
        public class _线程列表 : IDisposable
        {
            public _数据 数据;
            public TreeViewItem 控件节点;
            public void Dispose()
            {
                if (数据 != null)
                    数据.Dispose();
                MainWindow.This.线程列表.Items.Remove(控件节点);
                Win32.启用鼠标加速();
                控件节点 = null;
            }
        }

    }
}

public enum 数据级别
{
    数据, 方案, 步骤, 方法
}





